﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using LumenLiquid.Language;
using System.Diagnostics;
using System.Collections.Generic;
using System.Windows.Forms;

/***********************************
 *      CShark & VisibleBasix      *
 ***********************************/

namespace LumenLiquid
{
    /// <summary>
    /// Initializes all Vars needed for the game and menues
    /// </summary>
    public class Initialisation : IDrawable
    {
        /// <summary>
        /// Was the initialisator called allready?
        /// </summary>
        private bool _initialized = false;

        /// <summary>
        /// The backgroundworker for the thread
        /// </summary>
        System.ComponentModel.BackgroundWorker _initializer = new System.ComponentModel.BackgroundWorker();

        /// <summary>
        /// The backgroundworker for changing the screensize
        /// </summary>
        System.ComponentModel.BackgroundWorker _screensizeUpdater = new System.ComponentModel.BackgroundWorker();

        /// <summary>
        /// The rendertarget for the loading model
        /// </summary>
        RenderTarget2D _renderTarget;
        /// <summary>
        /// The finall texture for the rendered loading model
        /// </summary>
        Texture2D _tloader;

        /// <summary>
        /// The model for the loading animation
        /// </summary>
        Model _mloader;
        /// <summary>
        /// Matrix for rendering the loading animation
        /// </summary>
        Matrix _world, _view, _projection;
        /// <summary>
        /// The Size of the Render Target
        /// </summary>
        Vector2 _targetSize;
        /// <summary>
        /// The Position of the Camera
        /// </summary>
        Vector3 _cameraPos;
        /// <summary>
        /// The expected rotaition per second
        /// </summary>
        Vector3 _rotationBase;

        /// <summary>
        /// The rotation of the dice on X,Y and Z
        /// </summary>
        Vector3 _rotation = new Vector3(0);

        /// <summary>
        /// Initializes the vars in a new thread
        /// </summary>
        public void Init(GameTime gametime)
        {
            _targetSize = new Vector2(150, 150);
            _cameraPos = new Vector3(0, 0, 25);
            _rotationBase = new Vector3(90, 90, 0);

            //Initialize the rendertarget and matrixes
            _renderTarget = new RenderTarget2D(Global.Device, (int)_targetSize.X, (int)_targetSize.Y, true, SurfaceFormat.Rgba64, DepthFormat.Depth16);
            _view = Matrix.CreateLookAt(_cameraPos, new Vector3(0), Vector3.Up);
            _projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), _targetSize.X / _targetSize.Y, 0.1f, 100f);
            _mloader = Global.Content.Load<Model>(Global.content_model_loading);

            if (!_initializer.IsBusy && !Global.Initialized)
            {
                _initializer.DoWork += new System.ComponentModel.DoWorkEventHandler(Initialize);
                _initializer.RunWorkerAsync();
            }
            _initialized = true;
        }

        /// <summary>
        /// Returns whether the Initializor was called allready
        /// </summary>
        public bool Initialized
        {
            get { return _initialized; }
        }

        /// <summary>
        /// Loads all Contentfiles over a asynchroniusly thread - make the vars volatile
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Initialize(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            bool success;

            //Load Language
            #region Language
            AppDomainSetup mySetup = new AppDomainSetup();
            AppDomain myAppDomain;
            System.Security.Policy.Evidence myEvidence = AppDomain.CurrentDomain.Evidence;
            string AppPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);


            mySetup.ApplicationBase = AppPath;
            myAppDomain = AppDomain.CreateDomain("LanguagePacks", myEvidence, mySetup);

            try
            {
                try
                {
                    Global.LanguageFile = (ILanguage)myAppDomain.CreateInstanceFromAndUnwrap(AppPath + @"\" + Global.Settings.HeadKey.get_GetValue("Language") + "Lang.dll", "LanguagePack.LanguageModule");
                }
                catch
                {
                    Global.LanguageFile = (ILanguage)myAppDomain.CreateInstanceFromAndUnwrap(AppPath + @"\EnglishLang.dll", "LanguagePack.LanguageModule");
                    Global.Settings.HeadKey.AddValue(new FileIO.File.Key.Value("Language", "English"));
                }

                Global.DebugLog.Log("Language DLL loaded successfuly");
            }
            catch
            {
                Global.DebugLog.Log("Failed to load Language DLL");
                Global.Maingame.Exit();
            }

            mySetup = null; myAppDomain = null; myEvidence = null;
            #endregion
            //Load Crusades-Font
            success = Global.FontManager.AddSpriteFont(Global.FontManagerConstants.Main_72, Global.content_fnt_main_72);
            Global.DebugLog.Log("Initialising Crusades_72:" + success);
            success = Global.FontManager.AddSpriteFont(Global.FontManagerConstants.Main_34, Global.content_fnt_main_34);
            Global.DebugLog.Log("Initialising Crusades_34:" + success);
            success = Global.FontManager.AddSpriteFont(Global.FontManagerConstants.Main_28, Global.content_fnt_main_28);
            Global.DebugLog.Log("Initialising Crusades_28:" + success);

            #region Here the Initialisations
            #region Cursors
            Global.Cursor_DefaultCursor = Global.Content.Load<Texture2D>(Global.content_cur_Default);
            Global.DebugLog.Log("Default Cursor loaded");
            #endregion

            #region MainMenu
            //To save memory, load directly the right one.

            //Support for 16:9 and 16:10
            if (Global.Screensize.Y / 9 * 16 == Global.Screensize.X ||
                Global.Screensize.Y / 10 * 16 == Global.Screensize.X)
            {
                InitMenu16x9();

                Global.DebugLog.Log("Initializing with 16x9");

            }
            else //Otherwise it's a 4:3, 5:3 or 5:4 format. Use 4:3 background.
            {
                InitMenu4x3();

                Global.DebugLog.Log("Initializing with 4x3");

            }

            InitTextures();
            InitControlSizes();
            Global.DebugLog.Log("Initialized Textures");

            InitMenues();
            #endregion

            #region Colors
            Global.Menu.btn_normal = Color.FromNonPremultiplied(Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_normal").Split(';')[0]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_normal").Split(';')[1]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_normal").Split(';')[2]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_normal").Split(';')[3]));
            Global.Menu.btn_hovered = Color.FromNonPremultiplied(Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_hovered").Split(';')[0]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_hovered").Split(';')[1]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_hovered").Split(';')[2]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_hovered").Split(';')[3]));
            Global.Menu.btn_clicked = Color.FromNonPremultiplied(Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_clicked").Split(';')[0]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_clicked").Split(';')[1]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_clicked").Split(';')[2]), Convert.ToInt32(Global.Settings.HeadKey.get_GetKey("Colors").get_GetValue("btn_clicked").Split(';')[3]));
            #endregion
            #endregion

            InitAudio();
            System.Threading.Thread.Sleep(5000);
            Global.Initialized = true;
        }

        /// <summary>
        /// Changes the ressources according to the screensize asynchroniusly
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateScreensize(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            //Support for 16:9 and 16:10
            if (Global.Screensize.Y / 9 * 16 == Global.Screensize.X ||
                Global.Screensize.Y / 10 * 16 == Global.Screensize.X)
            {
                InitMenu16x9();

                Global.DebugLog.Log("Changing Screensize to 16x9");

            }
            else //Otherwise it's a 4:3, 5:3 or 5:4 format. Use 4:3 background.
            {
                InitMenu4x3();

                Global.DebugLog.Log("Changing Screensize to 4x3");

            }
        }

        /// <summary>
        /// Renders the Initializing screen
        /// </summary>
        /// <param name="gametime">The gametime</param>
        public void Draw(GameTime gametime)
        {
            if (Global.FontManager.Contains(Global.FontManagerConstants.Main_72) == true)
            {
                //Render the loading object and paint it to the screen
                Global.SpriteBatch.End();
                Global.Device.SetRenderTarget(_renderTarget);
                Global.Device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 5.0f, 0);  //Clear backbuffer, but Z-Buffer doesn't run, anyway


                #region Drawing the dice
                foreach (ModelMesh mesh in _mloader.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.World = _world;
                        effect.View = _view;
                        effect.Projection = _projection;
                        effect.EnableDefaultLighting();
                    }

                    mesh.Draw();
                }
                #endregion
                Global.Device.SetRenderTarget(null);

                _tloader = (Texture2D)_renderTarget;

                Global.Device.Clear(Color.Black);
                Global.SpriteBatch.Begin();

                Global.SpriteBatch.Draw(_tloader, Global.Screensize - new Vector2(150), Color.White);


                Global.FontManager[Global.FontManagerConstants.Main_72].DrawString(Global.LanguageFile.Loading, new Vector2(0, Global.Screensize.Y - Global.FontManager[Global.FontManagerConstants.Main_72].MeasureString(Global.LanguageFile.Loading).Y), Color.DarkOrange);
                Global.FontManager[Global.FontManagerConstants.Main_72].DrawString(Global.LanguageFile.GameTitle, new Vector2(Global.Screensize.X / 2 - Global.FontManager[Global.FontManagerConstants.Main_72].MeasureString(Global.LanguageFile.GameTitle).X / 2, 5), Color.DarkOrange);
            }
        }

        /// <summary>
        /// Updates this class
        /// </summary>
        /// <param name="gametime"></param>
        public void Update(GameTime gametime)
        {
            _rotation.X += MathHelper.ToRadians((float)gametime.ElapsedGameTime.TotalSeconds * _rotationBase.X);
            _rotation.Y += MathHelper.ToRadians((float)gametime.ElapsedGameTime.TotalSeconds * _rotationBase.Y);
            _rotation.Z += MathHelper.ToRadians((float)gametime.ElapsedGameTime.TotalSeconds * _rotationBase.Z);

            _world = Matrix.Identity * Matrix.CreateRotationX(_rotation.X) * Matrix.CreateRotationY(_rotation.Y) * Matrix.CreateRotationZ(_rotation.Z);
        }

        /// <summary>
        /// Will be called after the screensize of the game has changed to load the changed textures
        /// </summary>
        public void ScreensizeChanged()
        {
            _screensizeUpdater.DoWork += new System.ComponentModel.DoWorkEventHandler(UpdateScreensize);
            _screensizeUpdater.RunWorkerAsync();
        }


        #region Initialisations
        #region Menu
        void InitMenu16x9()
        {
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_Background, Global.Content.Load<Texture2D>(Global.content_img_mnu_Back16x9));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_Button, Global.Content.Load<Texture2D>(Global.content_img_buttonbackground16x9));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_SliderBackground, Global.Content.Load<Texture2D>(Global.content_img_sliderbackground16x9));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_Slider, Global.Content.Load<Texture2D>(Global.content_img_slider));

            Global.FontManagerConstants.Main_buttons = Global.FontManagerConstants.Main_34;

            Global.Menu.mnu_controlspacehorizontal = Global.Menu.mnu_controlspacehorizontal_16x9;
            Global.Menu.mnu_controlspaceLowerHorizontal = Global.Menu.mnu_controlspaceLower16x9;
        }

        void InitMenu4x3()
        {
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_Button, Global.Content.Load<Texture2D>(Global.content_img_buttonbackground4x3));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_Background, Global.Content.Load<Texture2D>(Global.content_img_mnu_Back4x3));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_SliderBackground, Global.Content.Load<Texture2D>(Global.content_img_sliderbackground4x3));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_Slider, Global.Content.Load<Texture2D>(Global.content_img_slider));

            Global.FontManagerConstants.Main_buttons = Global.FontManagerConstants.Main_28;

            Global.Menu.mnu_controlspacehorizontal = Global.Menu.mnu_controlspacehorizontal_4x3;
            Global.Menu.mnu_controlspaceLowerHorizontal = Global.Menu.mnu_controlspaceLower4x3;
        }

        void InitControlSizes()
        {
            Global.Menu.mnu_defaultbuttonsize = Global.TextureManager.GetSize(Global.TexturemanagerConstants.mnu_Button);
            Global.Menu.mnu_defaultSlidersize = Global.TextureManager.GetSize(Global.TexturemanagerConstants.mnu_SliderBackground);
            Global.Menu.mnu_defaultListBoxSize = Global.TextureManager.GetSize(Global.TexturemanagerConstants.mnu_listbox);
        }

        void InitMenues()
        {
            Global.Menu.mnu_MainMenu.Init(null);
            Global.Menu.mnu_MainMenu.ControlClicked += new Global.ControlClicked(Global.Maingame.menucontrolclicked);
            Global.Menu.mnu_Options.Init(null);
            Global.Menu.mnu_opt_graphics.Init(null);
            Global.Menu.mnu_opt_sound.Init(null);
            Global.Menu.mnu_Credits.Init(null);
            Global.Menu.mnu_NewGame.Init(null);
            Global.Menu.mnu_LoadGame.Init(null);
            Global.Menu.mnu_opt_keyboard.Init(null);

            Global.DebugLog.Log("Menus initialized");
        }
        #endregion

        #region Audio
        void InitAudio()
        {
            List<string> Categories = new List<string>();
            Categories.AddRange(new string[] { "Default", "Music", "FX" });
            Global.AudioPlayer.Init(Global.Content.RootDirectory + "\\" + Global.content_audio_project, Categories);
            Global.AudioPlayer.AddWaveBank(Global.content_audio_music_wavebank);
            Global.AudioPlayer.AddSoundBank(Global.content_audio_mainmenu_soundbank);

            Global.DebugLog.Log("Audio Player initialized");
        }
        #endregion

        void InitTextures()
        {
            Global.TextureManager.Add(Global.TexturemanagerConstants.pxl_white, Global.Content.Load<Texture2D>(Global.content_pxl_white));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_listbox, Global.Content.Load<Texture2D>(Global.content_img_listbox));
            Global.TextureManager.Add(Global.TexturemanagerConstants.mnu_listbox_nav_def, Global.Content.Load<Texture2D>(Global.content_img_listbox_nav));
        }
        #endregion
    }
}
